import { Storage } from "./storage";
import { User, Post, Comment, ContentStatus } from './db';

interface Params {
  data?: any,
  noAuth?: boolean,
  useForm?: boolean,
  errMsg?: { [code: number]: string }
}

interface RequestSuccessCallbackResult<T> {
  data: T;
  header: { [index: string]: string };
  statusCode: number;
  errMsg: string;
}

export function handleErr(err: any) {
  if (err.em) {
    wx.showToast({
      title: err.em,
      icon: 'none'
    });
  }
}

export class API {
  static server = 'http://101.132.144.199:3000';

  static async fetch<T>(method: 'POST' | 'GET' | 'PUT' | 'DELETE', url: string, params?: Params) {
    url = url.startsWith('http') ? url : (this.server + url);
    console.log(`[${method}] ${url} WITH DATA:`, params?.data);
    return new Promise<RequestSuccessCallbackResult<T>>((resolve, reject) => {
      const wrapReject = (err: any) => {
        if (params?.errMsg && err.statusCode && params.errMsg[err.statusCode]) {
          reject({
            em: params.errMsg[err.statusCode]
          });
        } else {
          reject(err);
        }
      };
      wx.request({
        url,
        method,
        header: {
          Authorization: params?.noAuth ? '' : `Bearer ${Storage.get('jwt')}`,
          'Content-Type': params?.useForm ? 'application/x-www-form-urlencoded' : 'application/json',
        },
        data: params?.data,
        success: res => {
          if (res.statusCode < 400) {
            resolve(res as any);
          } else {
            wrapReject(res);
          }
        },
        fail: res => {
          wrapReject(res);
        }
      });
    });
  }

  // 登录
  static async login() {
    return new Promise<User>((resolve, reject) => {
      wx.login({
        success: async res => {
          let response = await this.fetch<{ jwt: string, user: User }>('POST', '/user/login', { data: { code: res.code } });
          Storage.save('jwt', response.data.jwt);
          Storage.save('role', response.data.user.role);
          resolve(response.data.user);
        },
        fail: reject
      });
    });
  }

  // 获取用户信息
  static async getUserInfo() {
    let response = await this.fetch<User>('GET', '/user/info');
    if (response.data.role != Storage.get('role')) {
      throw new Error('用户权限需要更新');
    }
    return response;
  }

  // 用户身份认证
  static async updateUserInfo(data: {
    //@IsString()
    //@Length(1, 10)
    name: string;

    //@IsString()
    //@Length(1, 20)
    school: string;

    //@IsString()
    //@Length(1, 20)
    schoolId: string;

    //@IsString()
    //@Length(1, 10)
    studentType: string;

    //@IsString()
    //@Length(4, 4)
    studentYear: string;

    //@IsString()
    //@Length(0, 20)
    shuVerify: string;
  }) {
    return this.fetch<User>('POST', '/user/info', {
      data, errMsg: {
        400: '输入的数据格式错误',
        450: '您已经验证过，请勿重复验证'
      }
    });
  }

  static async shuVerify(username: string, password: string): Promise<boolean> {
    try {
      let response = await this.fetch('POST', 'https://newsso.shu.edu.cn/login/eyJjbGllbnRJZCI6IldVSFdmcm50bldZSFpmelE1UXZYVUNWeSJ9', {
        data: { username, password },
        useForm: true,
        noAuth: true
      });
      return response.header['content-length'] === '0' || !('transfer-encoding' in response.header);
    } catch (e) {
      return false;
    }
  }

  // 发表帖子，文本内容先使用 ssw.js 里的预检筛一下
  static async publishPost(data: {
    // @IsString()
    // @Length(1)
    title: string;

    // @IsArray()
    images: [];

    // @IsBoolean()
    anonymous: boolean;

    // @IsString()
    // @Length(1)
    content: string;
  }) {
    return this.fetch<{ id: number }>('POST', '/post', {
      data,
      errMsg: {
        400: '帖子信息不符合要求'
      }
    });
  }

  // 获取帖子详情
  static async getPostInfo(id: number) {
    return this.fetch<Post>('GET', `/post/${id}`, {
      errMsg: {
        404: '帖子不存在'
      }
    });
  }

  // 获取最新动态，使用于下拉刷新
  static async getLastestPosts() {
    return this.fetch<Post[]>('GET', '/feed', {
      data: { count: 10 }
    });
  }

  // 获取帖子ID之前的动态，使用于触底加载，比如getLastestPosts获得了id[50-59]的帖子，用户触底就应该调用getPostsBefore(50)获取[40-49]的帖子
  static async getPostsBefore(before: number) {
    return this.fetch<Post[]>('GET', '/feed/more', {
      data: { count: 10, before }
    });
  }

  // 回复动态贴
  static async replyToPost(postid: number, content: string, images: string[]) {
    return this.fetch<{ id: number }>('POST', `/post/${postid}/comment`, {
      data: { content, images },
      errMsg: {
        404: '帖子不存在'
      }
    });
  }

  // 回复帖子下的评论
  static async replyToComment(postid: number, commentid: number, content: string, images: string[]) {
    return this.fetch<{ id: number }>('POST', `/post/${postid}/comment`, {
      data: { content, images, parent: commentid },
      errMsg: {
        404: '帖子不存在'
      }
    });
  }

  // 获取帖子下的评论，需要判断 Comment.status，被举报封禁则显示 `内容违规`，子评论正常显示
  static async getComments(postid: number) {
    return this.fetch<Comment[]>('GET', `/post/${postid}/comment`);
  }

  // 点赞帖子
  static async upvotePost(postid: number) {
    return this.fetch<{ id: number }>('POST', `/post/${postid}/upvote`, {
      errMsg: {
        450: '已经点赞过'
      }
    });
  }

  // 点赞帖子下的评论
  static async upvoteComment(postid: number, commentid: number) {
    return this.fetch<{ id: number }>('POST', `/post/${postid}/comment/${commentid}/upvote`, {
      errMsg: {
        450: '已经点赞过'
      }
    });
  }


  // text 长度需要 >= 2， before 为0获取最近的结果， 不为零获取此postid之前的搜索结果，参考 getPostsBefore 说明
  static async searchText(text: string, before: number) {
    return this.fetch<Post[]>('GET', `/feed/search?count=10&before=${before}&text=${encodeURIComponent(text)}`);
  }

  // 修改帖子状态，status 指定审核通过/封禁等操作
  static async adminChangePostStatus(postid: number, status: ContentStatus) {
    return this.fetch<void>('POST', `/admin/post/${postid}/status/${status}`, {
      errMsg: {
        450: 'ContentStatus 状态非法'
      }
    });
  }

  // 修改评论状态，status 指定封禁等操作
  static async adminChangeCommentStatus(postid: number, status: ContentStatus) {
    return this.fetch<void>('POST', `/admin/comment/${postid}/status/${status}`, {
      errMsg: {
        450: 'ContentStatus 状态非法'
      }
    });
  }
}

// for tests
(wx as any).API = API;